﻿/****************************************************************************************
 * Name         :   3D Image Processor
 * Author       :   Shah-nawaj Shuhan
 * Description  :   The application uses two cameras to capture images, Cameras should be
 *                  aligned horizentally. Camera seperation should be around 3 inch. The
 *                  application captures two 2D images and combines them to form Red Cyan
 *                  sterioscopic 3D image.
 * Company      :   Onuprova
 * URL          :   http://onuprova.com
 * 
 * References   :   AForge.NET is used to capture Image from webcam using Directshow
 *                  Unsafe pixel access: http://www.dreamincode.net/forums/topic/14788-c%23-fast-acces-to-bitmap-pixels/
 ****************************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Threading;
using AForge.Video;
using AForge.Video.DirectShow;
using System.IO;
using System.Drawing.Imaging;
using System.Reflection;
using Onuprova.Anaglyphing.ImageProcessor;

namespace _3D_Processor
{
    public partial class MainForm : Form
    {

        private bool isReady = false;

        public static AnaglyphConfiguration AnaglyphConfig;
        //Colour filters
        public static ColourFilterConfiguration LeftFilter;
        public static ColourFilterConfiguration RightFilter;

        public MainForm()
        {
            InitializeComponent();
            //Initialize the sound class
            AppSound.Initialize();
            //Initialize Camera list
            InitializeCamList();
            //Load the colour scheme
            ColourSchemes.SelectedIndex = Properties.Settings.Default.ColourScheme;
            //Load calibration information
            AnaglyphConfig = Properties.Settings.Default.AnaglyphConfig;
            if (AnaglyphConfig == null)
            {
                AnaglyphConfig = new AnaglyphConfiguration();
                AnaglyphConfig.ViewPort = new Rectangle(0, 0, 640, 480);
                AnaglyphConfig.LeftCalibrationInfo = new AdjustmentParameter();
                AnaglyphConfig.RightCalibrationInfo = new AdjustmentParameter();
                AnaglyphConfig.LeftCalibrationInfo.Transformation = new TransformFactor();
                AnaglyphConfig.RightCalibrationInfo.Transformation = new TransformFactor();
                AnaglyphConfig.LeftCalibrationInfo.Transformation.ZoomFactor = 1;
                AnaglyphConfig.RightCalibrationInfo.Transformation.ZoomFactor = 1;
                AnaglyphConfig.LeftCalibrationInfo.ColourFilter = LeftFilter;
                AnaglyphConfig.RightCalibrationInfo.ColourFilter = RightFilter;
                Properties.Settings.Default.AnaglyphConfig = AnaglyphConfig;
                Properties.Settings.Default.Save();
            }
            //Load file location
            LoadFileLocation();
        }

        private void LoadFileLocation()
        {
            string DirectoryPath = Properties.Settings.Default.ImageDirectory;
            if (DirectoryPath == "")
            {
                BrowseButton_Click(BrowseButton, null);
            }
            else if (!System.IO.Directory.Exists(DirectoryPath))
            {
                BrowseButton_Click(BrowseButton, null);
            }
            else
            {
                LocationLabel.Text = DirectoryPath;
            }
        }

        private void InitializeCamList()
        {
            // show device list
            try
            {
                //Initialize the cameras
                Camera.Initialize();

                if (Camera.Devices.Count == 0)
                {
                    throw new Exception();
                }

                for (int i = 1, n = Camera.Devices.Count; i <= n; i++)
                {
                    string cameraName = i + " : " + Camera.Devices[i - 1].Name;

                    LeftCamCombo.Items.Add(cameraName);
                    RightCamCombo.Items.Add(cameraName);
                }

                // check cameras count
                if (Camera.Devices.Count == 1)
                {
                    RightCamCombo.Items.Clear();
                    isReady = false;
                    RightCamCombo.Items.Add("Only one camera found");
                    RightCamCombo.SelectedIndex = 0;
                    RightCamCombo.Enabled = false;
                }
                else
                {
                    RightCamCombo.SelectedIndex = 1;
                    isReady = true;
                }
                LeftCamCombo.SelectedIndex = 0;
            }
            catch
            {
                isReady = false;
                CaptureButton.Enabled = false;
                RecordButton.Enabled = false;

                LeftCamCombo.Items.Add("No cameras found");
                RightCamCombo.Items.Add("No cameras found");

                LeftCamCombo.SelectedIndex = 0;
                RightCamCombo.SelectedIndex = 0;

                LeftCamCombo.Enabled = false;
                RightCamCombo.Enabled = false;
            }
            finally
            {
                if (isReady)
                {
                    StartCameras();
                    LeftCamCombo.SelectedIndexChanged += new EventHandler(CamCombo_SelectedIndexChanged);
                    RightCamCombo.SelectedIndexChanged += new EventHandler(CamCombo_SelectedIndexChanged);
                }
                else
                {
                    MessageBox.Show("Sorry, your system is not ready for 3D capturing.\n You must have 2 cameras installed.\n Please check your camera connections and try again", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
                    Application.Exit();
                }
            }
        }

        #region Form Customization

        private const int WM_NCHITTEST = 0X84;
        private const int HTCLIENT = 0x1;
        private const int HTCAPTION = 0x2;
        private const int HTCLOSE = 20;
        private const int HTREDUCE = 0x8;

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_NCHITTEST)
            {
                base.WndProc(ref m);
                if (m.Result == (IntPtr)HTCLIENT && (MousePosition.Y - this.Top) < 40)
                {
                    m.Result = (IntPtr)HTCAPTION;
                    return;
                }
            }
            base.WndProc(ref m);
        }
        #endregion

        // Start cameras
        private void StartCameras()
        {
            // create first video source
            VideoCaptureDevice videoSource1 = new VideoCaptureDevice(Camera.Devices[LeftCamCombo.SelectedIndex].MonikerString);
            videoSource1.DesiredFrameRate = 10;

            LeftCamWindow.VideoSource = videoSource1;
            LeftCamWindow.Start();

            // create second video source
            if (RightCamCombo.Enabled == true)
            {
                System.Threading.Thread.Sleep(500);

                VideoCaptureDevice videoSource2 = new VideoCaptureDevice(Camera.Devices[RightCamCombo.SelectedIndex].MonikerString);
                videoSource2.DesiredFrameRate = 10;

                RightCamWindow.VideoSource = videoSource2;
                RightCamWindow.Start();
            }
            if (RightCamCombo.SelectedIndex == LeftCamCombo.SelectedIndex)
            {
                CaptureButton.Enabled = false;
                RecordButton.Enabled = false;
                StatusL.Text = "Camera conflicted (Please select two different camera)";
            }
            else
            {
                Thread.Sleep(1000);
                CaptureButton.Enabled = true;
                RecordButton.Enabled = true;
                StatusL.Text = "Ready";
            }
        }

        // Stop cameras
        private void StopCameras()
        {
           LeftCamWindow.SignalToStop();
           RightCamWindow.SignalToStop();

           LeftCamWindow.WaitForStop();
           RightCamWindow.WaitForStop();

           CaptureButton.Enabled = false;
           RecordButton.Enabled = false;
        }

        void Hold()
        {
            //Browse.Enabled = false;
            //Normalb.Enabled = false;
            //RedFilterb.Enabled = false;
            //CyanFilterb.Enabled = false;
            foreach (Control b in this.Controls)
            {
                b.Enabled = false;
            }
        }

        void ok()
        {
            //Browse.Enabled = true;
            //Normalb.Enabled = true;
            //RedFilterb.Enabled = true;
            //CyanFilterb.Enabled = true;
            foreach (Control b in this.Controls)
            {
                b.Enabled = true;
            }
        }

        #region Image Capturing Subroutine

        CaptureModes CaptureMode;

        /// <summary>
        /// Capture an image after a fixed period of time
        /// </summary>
        /// <param name="Seconds"></param>
        private void TimerCapture(Object Second)
        {
            int Seconds = (int)Second;
            IntHandler CountDownUpdater = new IntHandler(UpdateCountDown);
            IntHandler UpdatePC = new IntHandler(ProcessCompleted);

            while (Seconds > 0)
            {
                if (Seconds < 6 && Seconds > 0)
                {
                    System.Media.SystemSounds.Beep.Play();
                }
                if (isCancle) { this.Invoke(UpdatePC, new Object[] { 1 }); return; }
                try
                {
                    this.Invoke(CountDownUpdater, new Object[] { Seconds });
                }
                catch {}
                Thread.Sleep(1000);
                Seconds--;
            }
            try
            {
                this.Invoke(CountDownUpdater, new Object[] { Seconds });
            }
            catch { }
            Capture();
            try
            {
                this.Invoke(UpdatePC, new Object[] { 1 });
            }
            catch { }
        }

        private void UpdateCountDown(int i)
        {
            if (window != null && window.IsDisposed == false && window.Visible)
            {
                window.CountDownPan.Visible = true;
                window.CountDownLbl.Text = i.ToString();
            }
        }

        private void ProcessCompleted(int i)
        {
            CaptureButton.Image = Properties.Resources.Image_Capture;
            if(window!=null)
            window.CountDownPan.Visible = false;
        }
        /// <summary>
        /// Capture image sequence
        /// </summary>
        /// <param name="Params"></param>
        private void SequenceCapture(Object Params)
        {
            Object[] Objs = (Object[])Params;
            int Intervel = (int)Objs[0];
            int Duration = (int)Objs[1];
            IntHandler CountDownUpdater = new IntHandler(UpdateCountDown);
            IntHandler UpdatePC = new IntHandler(ProcessCompleted);

            Capture();
            while (Duration >= Intervel)
            {
                int Seconds = Intervel;
                while (Seconds > 0)
                {
                    if (Seconds < 6 && Seconds > 0)
                    {
                        System.Media.SystemSounds.Beep.Play();
                    }
                    if (isCancle) { this.Invoke(UpdatePC, new Object[] { 1 }); return; }
                    try
                    {
                        this.Invoke(CountDownUpdater, new Object[] { Duration });
                    }
                    catch { }
                    Thread.Sleep(1000);
                    Seconds--;
                    Duration--;
                }
                try
                {
                    this.Invoke(CountDownUpdater, new Object[] { Duration });
                }
                catch { }
                Capture();
            }
            try
            {
                this.Invoke(UpdatePC, new Object[] { 1 });
            }
            catch { }
        }

        /// <summary>
        /// Capture an Image
        /// </summary>
        /// <returns></returns>
        new private bool Capture()
        {
            StringHandler StatusUpdate = new StringHandler(UpdateStatus);
            Bitmap lbmp = LeftCamWindow.GetCurrentVideoFrame();
            Bitmap rbmp = RightCamWindow.GetCurrentVideoFrame();

            //To eleminate the error when the left or right camera has stoped
            if (lbmp == null || rbmp == null)
            {
                MessageBox.Show("One or more camera has stoped working. Please select two active cameras to capture.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            RightImages.Add(rbmp);
            LeftImages.Add(lbmp);
            AppSound.Play();
            this.Invoke(StatusUpdate, new Object[] { "Processing (" + (LeftImages.Count - 1) + " in que)" });
            return true;
        }
        /// <summary>
        /// Image Capture modes
        /// </summary>
        enum CaptureModes
        {
            SingleShot,
            Sequence,
            Timer
        }

        #endregion

        #region Image Processing Subroutine

        /// <summary>
        /// Used by status updater
        /// </summary>
        /// <param name="str"></param>
        private delegate void StringHandler(string str);
        /// <summary>
        /// Actually used for status updater only
        /// </summary>
        /// <param name="progress"></param>
        private delegate void IntHandler(int progress);
        /// <summary>
        /// Update the 3D stereo preview picturebox
        /// </summary>
        /// <param name="StereoImage"></param>
        private delegate void ImageHandler(Image StereoImage);

        /// <summary>
        /// Image list to process
        /// </summary>
        public static List<Bitmap> LeftImages;
        public static List<Bitmap> RightImages;

        /// <summary>
        /// The flag to say if the processor is busy or not
        /// </summary>
        bool isBusy = false;

        /// <summary>
        /// Shuting the application down
        /// </summary>
        bool ShutingDown = false;

        /// <summary>
        /// This method will be called on a seperate thread to
        /// process stereoscopic images to create a Red Cyan 3D Image
        /// </summary>
        /// <returns></returns>
        private void StartProcessingLoop()
        {
            StringHandler StatusUpdate = new StringHandler(UpdateStatus);
            while (true)
            {
                if (ShutingDown) return;

                if (LeftImages.Count == 0)
                {
                    isBusy = false;
                    try { this.Invoke(StatusUpdate, new Object[] { "Ready" }); }
                    catch { return; }
                    System.Threading.Thread.Sleep(100);
                    continue;
                }
                isBusy = true;
                this.Invoke(StatusUpdate, new Object[] { "Processing (" + (LeftImages.Count - 1) + " in que)" });
                //Take the first image in que for processing
                Bitmap LeftImage = LeftImages[0];
                Bitmap RightImage = RightImages[0];
                if (ProcessStereo(LeftImage, RightImage))
                {
                    LeftImages.Remove(LeftImages[0]);
                    RightImages.Remove(RightImages[0]);
                    LeftImage.Dispose();
                    RightImage.Dispose();
                }
                else
                {
                    if (ShutingDown) return;
                    StringHandler DialogueHandler = new StringHandler(ShowDialogue);
                    //The path is not assigned may be, so lets check
                    string ImagePath = Properties.Settings.Default.ImageDirectory;
                    if (ImagePath == "")
                    {
                        this.Invoke(DialogueHandler, new Object[] { "Please set the image directory and then click to start processor again" });
                        return;
                    }
                    if (!System.IO.Directory.Exists(ImagePath))
                    {
                        this.Invoke(DialogueHandler, new Object[] { "The selected directory doesn't exist. Please set the image directory and then click to start processor again" });
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// Update status label
        /// </summary>
        /// <param name="status"></param>
        private void UpdateStatus(string status)
        {
            try
            {
                StatusL.Text = status;
            }
            catch { }
        }
        /// <summary>
        /// Update status progressbar
        /// </summary>
        /// <param name="Progress"></param>
        private void UpdateProgress(int Progress)
        {
            try
            {
                if (Progress > 100) Progress = 100;
                StatusP.Value = Progress;
                if (Progress == 100) StatusP.Visible = false; else StatusP.Visible = true;
            }
            catch { }
        }
        /// <summary>
        /// Show a dialogue box with the message
        /// </summary>
        /// <param name="msg"></param>
        private void ShowDialogue(string msg)
        {
            MessageBox.Show(msg, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
            StartProcessorButton.Enabled = true;
            StartProcessorButton.Image = Properties.Resources.inactive_working;
        }

        PreviewWindow window;
        /// <summary>
        /// Update the Stereo Preview window
        /// </summary>
        /// <param name="StereoImage"></param>
        private void UpdateStereoImage(Image StereoImage)
        {
            //Edited to update on new window
            try
            {
                if (window != null && window.IsDisposed == false && window.Visible)
                    window.StereoPreviewWindow.Image = StereoImage;
            }
            catch { }
            AddFrame((Bitmap)StereoImage);
        }

        /// <summary>
        /// Main processor that takes images to process and save the images
        /// </summary>
        /// <param name="leftImage"></param>
        /// <param name="rightImage"></param>
        /// <returns></returns>
        private bool ProcessStereo(Bitmap leftImage, Bitmap rightImage)
        {
            string ImagePath = Properties.Settings.Default.ImageDirectory;
            if (ImagePath == "")
                return false; //I haven't found the directory to save the image so stopping imediately and returning false
            if (!System.IO.Directory.Exists(ImagePath)) return false;
            if (ImagePath[ImagePath.Length - 1] != '\\') ImagePath = ImagePath + "\\";

            long num=1;
            string IP = ImagePath + "Image3D " + num + ".png";
            while (System.IO.File.Exists(IP))
            {
                if (ShutingDown) return false;
                num++;
                IP = ImagePath + "Image3D " + num + ".png";
            }
            ImagePath = IP;

            //Removed and added to ImageProcessor
            Bitmap LeftBmp=(Bitmap)leftImage.Clone();
            Bitmap RightBmp = (Bitmap)rightImage.Clone();
            Bitmap FBmp = ImageProcessor.GetAnaglyph(LeftBmp, RightBmp, AnaglyphConfig);
            LeftBmp.Dispose();
            RightBmp.Dispose();

            ImageHandler StereoHandler = new ImageHandler(UpdateStereoImage);
            //UI invoking takes time but I can not avoid this invoking
            this.Invoke(StereoHandler, new Object[] { FBmp.Clone() });
            try
            {
                //Image img = (Image)FBmp;
                //string software = "Onuprova Red Cyan 3D Camera";
                //System.Text.ASCIIEncoding encoder = new System.Text.ASCIIEncoding();
                ////Add software
                //img.SetPropertyItem(CreatePropertyItem(0x0131, 2, software.Length + 1, encoder.GetBytes(software)));
                ////Create Encoder params
                //EncoderParameter quality = new EncoderParameter(Encoder.Quality, 100L);//Max quality
                ////Add params to a list
                //EncoderParameters eparams = new EncoderParameters();
                //eparams.Param = new EncoderParameter[] { quality };
                ////Get the codec Info
                //ImageCodecInfo iEncoder = FindEncoder(ImageFormat.Jpeg);
                ////Save image
                //img.Save(ImagePath, iEncoder, eparams);
                //img.Dispose();
                FBmp.Save(ImagePath, System.Drawing.Imaging.ImageFormat.Png);
            }
            catch
            {
                return false;
            }
            FBmp.Dispose();
            return true;
        }

        #endregion

        #region Create Property Item

        public static ImageCodecInfo FindEncoder(ImageFormat format)
        {

            if (format == null)
                throw new ArgumentNullException("format");
            foreach (ImageCodecInfo codec in ImageCodecInfo.GetImageEncoders())
            {
                if (codec.FormatID.Equals(format.Guid))
                {
                    return codec;
                }
            }
            return null;
        }

        // *********************************************************************
        // See more about Exif Properties in .Net at
        // http://www.pixvillage.com/blogs/devblog/archive/2005/03/27/176.aspx
        // *********************************************************************

        private static Image propertyImage;

        private static Image PropertyImage
        {
            get
            {
                if (propertyImage == null)
                    propertyImage = LoadPropertyImage();
                return propertyImage;
            }
        }

        private static Image LoadPropertyImage()
        {
            // Gets the current assembly, retrieves the stream for the resource and loads the associated image.
            Assembly currentAssembly = Assembly.GetExecutingAssembly();
            //using (Stream propertyStream = currentAssembly.GetManifestResourceStream(currentAssembly.GetName().Name + "." + "logo.png"))
            using (Image resourceImage = (Image)Properties.Resources.feedback1)
            {
                // Creates a lightweight (1x1 pixel) bitmap with a single, empty exif property item.
                // This bitmap will remain in memory during the entire application runtime.
                Image propertyImage = new Bitmap(1, 1);
                PropertyItem propertyItem = resourceImage.PropertyItems[0];
                propertyItem.Id = 0;
                propertyItem.Type = 0;
                propertyItem.Len = 0;
                propertyItem.Value = new byte[0];

                propertyImage.SetPropertyItem(propertyItem);

                return propertyImage;
            }
        }

        /// <summary>
        /// Creates an empty property item.
        /// </summary>
        /// <returns>A new, empty instance of the <see cref="PropertyItem"/> class.</returns>
        public static PropertyItem CreateNewPropertyItem()
        {
            return PropertyImage.PropertyItems[0];
        }

        /// <summary>
        /// Creates a new property item having the given id, type and value.
        /// </summary>
        /// <param name="id">The identifier of the property item.</param>
        /// <param name="type">The type of value the property item does contain.</param>
        /// <param name="len">The length of the property value.</param>
        /// <param name="value">The property value.</param>
        /// <returns>A new, initialized, instance of the <see cref="PropertyItem"/> class.</returns>
        public static PropertyItem CreatePropertyItem(int id, short type, int len, byte[] value)
        {
            PropertyItem property = CreateNewPropertyItem();
            property.Id = id;
            property.Type = type;
            property.Len = len;
            property.Value = value;
            return property;
        }

        #endregion

        #region Real Time Preview Subroutine

        bool IsRealTimeOn = false;
        bool StopRealTime = false;
        /// <summary>
        /// This method will update the 3D preview display in real time
        /// </summary>
        private void RealTimeShow()
        {
            Bitmap lbmp = null, rbmp = null;
            ImageHandler StereoHandler = new ImageHandler(UpdateStereoImage);
            while (!ShutingDown)
            {
                IsRealTimeOn = true;
                try
                {
                    lbmp = LeftCamWindow.GetCurrentVideoFrame();
                    rbmp = RightCamWindow.GetCurrentVideoFrame();
                }
                catch { Thread.Sleep(100); continue; }

                if (lbmp == null || rbmp == null) { Thread.Sleep(100); continue; }

                //Removed and executing from the ImageProcessor
                Bitmap FBmp = ImageProcessor.GetAnaglyph(lbmp, rbmp, AnaglyphConfig);

                try
                {
                    this.Invoke(StereoHandler, new Object[] { FBmp.Clone() });
                    if (StopRealTime) { IsRealTimeOn = false; return; }
                }
                catch { return; }
                FBmp.Dispose();
            }
        }
        
        #endregion

        /// <summary>
        /// If processor is down then start the processor menually
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StartProcessor_Click(object sender, EventArgs e)
        {
            StartProcessorButton.Enabled = false;
            StartProcessorButton.Image = Properties.Resources.active_working;
            Thread Th = new Thread(StartProcessingLoop);
            Th.Start();
        }

        /// <summary>
        /// Form has started
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            CaptureMode = CaptureModes.SingleShot;
            SIntervel.Enabled = false;
            SDuration.Enabled = false;
            TWait.Enabled = false;
            ModesTab.SelectedIndex = 0;
            LeftImages = new List<Bitmap>();
            RightImages = new List<Bitmap>();
            StartProcessorButton.Enabled = false;
            StartProcessorButton.Image = Properties.Resources.active_working;
            Thread Th = new Thread(StartProcessingLoop);
            Th.Start();
        }
        /// <summary>
        /// Close the threads
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (isBusy)
            {
                DialogResult dr = MessageBox.Show("There are " + LeftImages.Count + " images in que to be processed. If you exit the application, you will lose all unprocessed images. Do you really want to exit?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Information);
                if (dr == System.Windows.Forms.DialogResult.No)
                {
                    e.Cancel = true;
                    return;
                }
            }
            else if (RecordingStatus != ApplicationStatus.RecordingStopped)
            {
                DialogResult dr = MessageBox.Show("Vedio recording in progress. Do you really want to exit?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Information);
                if (dr == System.Windows.Forms.DialogResult.No)
                {
                    e.Cancel = true;
                    return;
                }
                else
                {
                    StopButton_Click(StopButton, null);
                }
            }
            ShutingDown = true;
            StopCameras();
        }
        /// <summary>
        /// Switch cameras
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CamCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            StopCameras();
            StartCameras();
        }
        /// <summary>
        /// Set the location to save files
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BrowseButton_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            if (LocationLabel.Text != "")
            {
                fbd.SelectedPath = LocationLabel.Text;
            }
            fbd.Description = "Please select the Image and Video output directory";
            System.Windows.Forms.DialogResult dr = fbd.ShowDialog();

            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                Properties.Settings.Default.ImageDirectory = fbd.SelectedPath;
                Properties.Settings.Default.Save();
                LocationLabel.Text = Properties.Settings.Default.ImageDirectory;
            }
            fbd.Dispose();
        }
        bool isCancle;
        /// <summary>
        /// Capture a Image
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CaptureImage_Click(object sender, EventArgs e)
        {
            if (CaptureButton.Image==Properties.Resources.cancleCapture)
            { isCancle = true; return; }
            isCancle = false;
            if (window == null || window.IsDisposed)
            {
                window = new PreviewWindow();
                window.MainAppForm = this;
            }
            window.Show();
            window.BringToFront();
            switch (CaptureMode)
            {
                case CaptureModes.SingleShot:
                    Capture();
                    break;
                case CaptureModes.Timer:
                    CaptureButton.Image = Properties.Resources.cancleCapture;
                    Thread th1 = new Thread(new ParameterizedThreadStart(TimerCapture));
                    th1.Start((int)TWait.Value);
                    break;
                case CaptureModes.Sequence:
                    if (SDuration.Value <= SIntervel.Value)
                    {
                        MessageBox.Show("Capture duration should be greater than the capture intervel", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
                        return;
                    }
                    CaptureButton.Image = Properties.Resources.cancleCapture;
                    Thread th2 = new Thread(new ParameterizedThreadStart(SequenceCapture));
                    th2.Start(new Object[] { (int)SIntervel.Value, (int)SDuration.Value });
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// If checked is changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Tab_CheckedChanged(object sender, EventArgs e)
        {
            TabControl Sender = (TabControl)sender;

            switch (Sender.SelectedTab.Name)
            {
                case "SingleShot":
                    CaptureMode = CaptureModes.SingleShot;
                    SIntervel.Enabled = false;
                    SDuration.Enabled = false;
                    TWait.Enabled = false;
                    break;
                case "SequenceShot":
                    CaptureMode = CaptureModes.Sequence;
                    SIntervel.Enabled = true;
                    SDuration.Enabled = true;
                    TWait.Enabled = false;
                    break;
                case "TimerShot":
                    CaptureMode = CaptureModes.Timer;
                    SIntervel.Enabled = false;
                    SDuration.Enabled = false;
                    TWait.Enabled = true;
                    break;
            }
        }
        /// <summary>
        /// Show tool tip
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FeedbackButton_MouseHover(object sender, EventArgs e)
        {
            ToolTips.Show("Feedback", CalibrationButton);
        }
        /// <summary>
        /// Promot to feedback
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FeedbackButton_Click(object sender, EventArgs e)
        {
            if (LeftCamWindow.IsRunning == true && RightCamWindow.IsRunning == true)
            {
                CalibrationWindow cw = new CalibrationWindow();
                cw.InitializeCalibration(LeftCamWindow.GetCurrentVideoFrame(), RightCamWindow.GetCurrentVideoFrame());
                cw.ShowDialog();
            }
            else
            {
                MessageBox.Show("Please select two active camera to start calibration", Application.ProductName, MessageBoxButtons.OK);
            }
        }

        /// <summary
        /// Handle menual image processing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mAdd_Click(object sender, EventArgs e)
        {
            Add_Menually am = new Add_Menually();
            System.Windows.Forms.DialogResult DR = am.ShowDialog(this);
            am.Dispose();
        }

        private void FeedbackButton_MouseLeave(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// Start real time preview
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StartRealTimePreview_Click(object sender, EventArgs e)
        {
            if (IsRealTimeOn)
            {
                StopRealTime = true;
                ToolTips.SetToolTip(PreviewButton, "Start Preview");
                PreviewButton.Image = Properties.Resources.previewer;
                return;
            }
            else
            {
                if (window == null || window.IsDisposed)
                {
                    window = new PreviewWindow();
                    window.MainAppForm = this;
                }
                window.Show();
                window.BringToFront();

                StopRealTime = false;
                Thread th = new Thread(RealTimeShow);
                th.Start();
                ToolTips.SetToolTip(PreviewButton, "Stop Real-time Preview");
                PreviewButton.Image = Properties.Resources.stopPreviewer;
                return;
            }
        }

        private void MinimizeButton_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void CloseButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Callback from preview window if closed by user
        /// </summary>
        public void PreviewWindowClosed()
        {
            try
            {
                if (CaptureButton.Image == Properties.Resources.cancleCapture)
                {
                    CaptureImage_Click(CaptureButton, null);
                }
            }
            catch { }
            try
            {
                if (RecordingStatus != ApplicationStatus.RecordingStopped)
                {
                    StopButton_Click(StopButton, null);
                }
            }
            catch { }
            try
            {
                if (IsRealTimeOn)
                {
                    StartRealTimePreview_Click(PreviewButton, null);
                }
            }
            catch { }
        }

        /// <summary>
        /// Colour scheme
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ColourSchemes_SelectedIndexChanged(object sender, EventArgs e)
        {
            ColourScheme Colourscheme = (ColourScheme)ColourSchemes.SelectedIndex;
            switch (Colourscheme)
            {
                case ColourScheme.GreenMagenta:
                    //Magenta filter on left image
                    LeftFilter = new ColourFilterConfiguration(1, 0, 1);
                    //Green filter on right image
                    RightFilter = new ColourFilterConfiguration(0, 1, 0);
                    break;
                case ColourScheme.MagentaCyan:
                    //Cyan filter on left image
                    LeftFilter = new ColourFilterConfiguration(0, 1, 0.5f);
                    //Magenta filter on right image
                    RightFilter = new ColourFilterConfiguration(1, 0, 0.5f);
                    break;
                case ColourScheme.RedBlue:
                    //Blue filter on left image
                    LeftFilter = new ColourFilterConfiguration(0, 0, 1);
                    //Red filter on right image
                    RightFilter = new ColourFilterConfiguration(1, 0, 0);
                    break;
                case ColourScheme.RedCyan:
                    //Cyan filter on left image
                    LeftFilter = new ColourFilterConfiguration(0, 1, 1);
                    //red filter on right image
                    RightFilter = new ColourFilterConfiguration(1, 0, 0);
                    break;
                case ColourScheme.RedGreen:
                    //Green filter on left image
                    LeftFilter = new ColourFilterConfiguration(0, 1, 0);
                    //Red filter on right image
                    RightFilter = new ColourFilterConfiguration(1, 0, 0);
                    break;
                default:
                    //Default selects red cyan
                    //Cyan filter on left image
                    LeftFilter = new ColourFilterConfiguration(0, 1, 1);
                    //red filter on right image
                    RightFilter = new ColourFilterConfiguration(1, 0, 0);
                    break;
            }
            if (AnaglyphConfig != null)
            {
                AnaglyphConfig.LeftCalibrationInfo.ColourFilter = LeftFilter;
                AnaglyphConfig.RightCalibrationInfo.ColourFilter = RightFilter;
            }
            Properties.Settings.Default.AnaglyphConfig = AnaglyphConfig;
            Properties.Settings.Default.ColourScheme = (int)Colourscheme;
            Properties.Settings.Default.Save();
        }

        /// <summary>
        /// Show about box
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AboutButton_Click(object sender, EventArgs e)
        {
            AboutOnuprova3DCamera about = new AboutOnuprova3DCamera();
            about.ShowDialog(this);
        }

        #region VideoRecording

        /// <summary>
        /// Only uses the recording statuses
        /// </summary>
        public ApplicationStatus RecordingStatus= ApplicationStatus.RecordingStopped;
        private AviWriter Writer;
        private Bitmap wBitmap;

        private void RecordButton_Click(object sender, EventArgs e)
        {
            if (LeftCamWindow.IsRunning == false || RightCamWindow.IsRunning == false)
            {
                MessageBox.Show("You need to select two active cameras to record video", Application.ProductName);
                return;
            }
            if (!IsRealTimeOn)
                StartRealTimePreview_Click(PreviewButton, null);
            switch (RecordingStatus)
            {
                case ApplicationStatus.RecordingStopped:
                    //Start new recording
                    string VideoPath = "";
                    if (!getVideoPath(out VideoPath)) return;
                    Writer = new AviWriter();
                    wBitmap = Writer.Open(VideoPath, 10, AnaglyphConfig.ViewPort.Width, AnaglyphConfig.ViewPort.Height);
                    StartProcessor_Click(StartProcessorButton, null);
                    RecordingStatus = ApplicationStatus.Recording;
                    RecordButton.Image = Properties.Resources.pause;
                    ToolTips.SetToolTip(RecordButton, "Pause Recording");
                    CaptureButton.Enabled = false;
                    LeftCamCombo.Enabled = false;
                    RightCamCombo.Enabled = false;
                    ColourSchemes.Enabled = false;
                    break;
                case ApplicationStatus.RecordingPaused:
                    RecordingStatus = ApplicationStatus.Recording;
                    RecordButton.Image = Properties.Resources.pause;
                    ToolTips.SetToolTip(RecordButton, "Pause Recording");
                    CaptureButton.Enabled = false;
                    LeftCamCombo.Enabled = false;
                    RightCamCombo.Enabled = false;
                    ColourSchemes.Enabled = false;
                    break;
                case ApplicationStatus.Recording:
                    RecordingStatus = ApplicationStatus.RecordingPaused;
                    RecordButton.Image = Properties.Resources.resume;
                    ToolTips.SetToolTip(RecordButton, "Resume Recording");
                    CaptureButton.Enabled = true;
                    LeftCamCombo.Enabled = true;
                    RightCamCombo.Enabled = true;
                    ColourSchemes.Enabled = true;
                    break;
            }
            
        }

        private void AddFrame(Bitmap bmp)
        {
            if (RecordingStatus == ApplicationStatus.Recording)
            {
                Bitmap buffer = (Bitmap)bmp.Clone();
                buffer.RotateFlip(RotateFlipType.Rotate180FlipX);
                Graphics g = Graphics.FromImage(wBitmap);
                //g.TranslateTransform(wBitmap.Width / 2, wBitmap.Height / 2);
                //g.RotateTransform(180);
                //g.TranslateTransform(-1 * (wBitmap.Width / 2), -1 * (wBitmap.Height / 2));
                g.DrawImage(buffer, new Rectangle(0, 0, wBitmap.Width, wBitmap.Height));
                Writer.AddFrame();
                g.Dispose();
                buffer.Dispose();
            }
        }

        private bool getVideoPath(out string videoPath)
        {
            videoPath = "";
            string VideoPath = Properties.Settings.Default.ImageDirectory;
            if (VideoPath == "")
            {
                MessageBox.Show("Please set the output directory and try again");
                return false; //I haven't found the directory to save the image so stopping imediately and returning false
            }
            if (!System.IO.Directory.Exists(VideoPath))
            {
                MessageBox.Show("Current output directory does not exist. Please set the output directory and try again");
                return false;
            }
            if (VideoPath[VideoPath.Length - 1] != '\\') VideoPath = VideoPath + "\\";

            long num = 1;
            string IP = VideoPath + "Video3D " + num + ".avi";
            while (System.IO.File.Exists(IP))
            {
                if (ShutingDown) return false;
                num++;
                IP = VideoPath + "Video3D " + num + ".avi";
            }
            VideoPath = IP;
            videoPath = VideoPath;
            return true;
        }

        private void StopButton_Click(object sender, EventArgs e)
        {
            if (RecordingStatus != ApplicationStatus.RecordingStopped)
            {
                Writer.Close();
                RecordingStatus = ApplicationStatus.RecordingStopped;
                RecordButton.Image = Properties.Resources.record;
                ToolTips.SetToolTip(RecordButton, "Start Recording");
                CaptureButton.Enabled = true;
                LeftCamCombo.Enabled = true;
                RightCamCombo.Enabled = true;
                ColourSchemes.Enabled = true;
            }
        }

        #endregion


    }
}
